home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / utility / utilmisc / shutdown.lzh / shutdown_5.1 / src / shutdown.c < prev    next >
C/C++ Source or Header  |  1996-12-02  |  13KB  |  545 lines

  1. /*
  2.    shutdown.c --- shutdown command.
  3.  
  4.    (c) Copyright 1995 SHW Wabnitz
  5.    Written by Bernhard Fastenrath (fasten@shw.com)
  6.  
  7.    This file may be distributed under the terms
  8.    of the GNU General Public License.
  9.  
  10.    History:
  11.     12-12-95, bf: fflush (stdout) added (for Syslog)
  12.     10-30-96, bf: shutdown delay
  13.     11-28-96, bf: message format changed
  14.     12-03-96, bf: gcc compatibility restored
  15. */
  16.  
  17. #if defined (__SASC)
  18. #include <dos.h>
  19. #endif
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <exec/types.h>
  24. #include <exec/memory.h>
  25. #include <intuition/intuition.h>
  26. #include <proto/exec.h>
  27. #include <proto/intuition.h>
  28.  
  29. #include "queue/queue.h"
  30. #include "queue/shutdown.h"
  31. #include "shutdown_cmd.h"
  32. #include <shutdownbase.h>
  33.  
  34. #if defined (__GNUC__)
  35. #include "queue/queue_inline.h"
  36. #elif defined (__SASC)
  37. #include "queue/queue_pragmas.h"
  38. #endif
  39.  
  40. #if defined (__GNUC__)
  41. #include <shutdown_inline.h>
  42. #elif defined (__SASC)
  43. #include <shutdown_pragma.h>
  44. #endif
  45.  
  46. #define SIGBREAKF_MASK ( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | \
  47.              SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
  48.  
  49. int Unmount (char *filesystem, int mode);
  50.  
  51. void GoDown (int time);
  52. void CleanUp (char *error);
  53. QMessage *BroadcastShutdownMsg (ULONG status, ULONG time);
  54.  
  55. struct IntuitionBase *IntuitionBase = NULL;
  56. struct Library *QueueBase = NULL;
  57. struct Library *ShutdownBase = NULL;
  58. struct timerequest *TimerReq = NULL;
  59. struct MsgPort *TimerPort = NULL;
  60. struct MsgPort *ShutdownPort = NULL;
  61. QHandle ShutdownHandle = NULL;
  62. ULONG TimerMask;
  63. ULONG TimerErr = 1;
  64. ULONG ShutdownMask;
  65. ULONG WaitMask;
  66. ULONG QueueSignal, QueueMask;
  67. int point_of_no_return = 0;
  68. char *ShutdownPortname = "Shutdown";
  69. int SpNameLen;
  70. char *CantAllocatePort = "Can't allocate signal or message port.\n";
  71. char *ShutdownCancelled = "shutdown cancelled.\n";
  72. char *OutOfMemory = "Out of memory.\n";
  73. char *SorryTooLate = "Too late to stop shutdown.\n";
  74. int MessageTimedOut = 0;
  75. int HaltFlag = HFLG_HALT;
  76. int SyncTime = 5;
  77. int MaxTime = 60;
  78. int ShutdownTime = 10;
  79. int UseShutdownLibFlag = 0;
  80. int AbortableFlag = 1;
  81. int FastBoot = 0;
  82. int UnmountMode = UMNT_INHIBIT;
  83. int Error;
  84. char *optarg = NULL;
  85.  
  86. int
  87. getopt (int argc, char *const *argv, const char *opts)
  88. {
  89.   static int pos = 0;
  90.   char *c;
  91.  
  92.   while (++pos < argc && argv[pos][0] != '-');
  93.   if (pos >= argc)
  94.     return -1;
  95.   if ((c = strchr (opts, (int) argv[pos][1])) == 0)
  96.     return (int) '?';
  97.   if (*(c+1) != ':')
  98.     return (int) *c;
  99.   if (strlen (argv[pos]) > 2)
  100.     optarg = argv[pos] + 2;
  101.   else if (pos+1 < argc)
  102.     optarg = argv[pos+1];
  103.   else
  104.     return (int) '?';
  105.   return (int) *c;
  106. }
  107.  
  108. ULONG
  109. PutAndGet (Message *msg, char *portname)
  110. {
  111.   struct MsgPort *prt, *reply_port;
  112.  
  113.   if (!(reply_port = CreateMsgPort ()))
  114.     return 1;
  115.   msg -> mn_ReplyPort = reply_port;
  116.  
  117.   Forbid ();
  118.   if (prt = FindPort (portname))
  119.   {
  120.     PutMsg (prt, msg);
  121.     Permit ();
  122.     do
  123.       WaitPort (reply_port);
  124.     while (!GetMsg (reply_port));
  125.   }
  126.   else
  127.     Permit ();
  128.  
  129.   DeleteMsgPort (reply_port);
  130.   return (ULONG) (prt ? 0 : 2);
  131. }
  132.  
  133. void
  134. CancelRunningShutdown (void)
  135. {
  136.   Message *msg;
  137.  
  138.   if (!(msg = AllocMem (sizeof (Message), MEMF_PUBLIC | MEMF_CLEAR)))
  139.     CleanUp (OutOfMemory);
  140.  
  141.   switch (PutAndGet (msg, ShutdownPortname))
  142.   {
  143.     case 0:
  144.       if (msg -> mn_Node.ln_Name == (APTR) -1)
  145.         CleanUp (SorryTooLate);
  146.       CleanUp (ShutdownCancelled);
  147.     case 1:
  148.       CleanUp (CantAllocatePort);
  149.     case 2:
  150.       CleanUp ("Shutdown is not running.\n");
  151.   }
  152.   FreeMem (msg, sizeof (Message));
  153. }
  154.  
  155. void
  156. CleanUp (char *error)
  157. {
  158.   QMessage *msg;
  159.  
  160.   if (error)
  161.     printf (error);
  162.   if (!TimerErr)
  163.     CloseDevice ((struct IORequest *) TimerReq);
  164.   if (TimerReq)
  165.     DeleteIORequest (TimerReq);
  166.   if (TimerPort)
  167.     DeleteMsgPort (TimerPort);
  168.   if (ShutdownPort)
  169.   {
  170.     if (ShutdownPort -> mp_Node.ln_Name)
  171.       FreeMem (ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  172.     RemPort (ShutdownPort);
  173.     DeleteMsgPort (ShutdownPort);
  174.   }
  175.   if (ShutdownHandle)
  176.   {
  177.     while (msg = QGetMsg (ShutdownHandle))
  178.       QFreeMsg (msg, sizeof (ShutdownMessage));
  179.     if (QClose (ShutdownHandle))
  180.     {
  181.       printf ("Exiting, waiting for replies.\n");
  182.       while (QClose (ShutdownHandle) > 0)
  183.       {
  184.         Delay (50);
  185.         while (msg = QGetMsg (ShutdownHandle))
  186.       QFreeMsg (msg, sizeof (ShutdownMessage));
  187.       }
  188.     }
  189.     FreeSignal (QueueSignal);
  190.   }
  191.   if (QueueBase)
  192.     CloseLibrary (QueueBase);
  193.   if (ShutdownBase)
  194.     CloseLibrary (ShutdownBase);
  195.   if (IntuitionBase)
  196.     CloseLibrary ((struct Library *) IntuitionBase);  
  197.   exit (error ? EXIT_FAILURE : EXIT_SUCCESS);
  198. }
  199.  
  200. int
  201. CancelShutdown (void)
  202. {
  203.   if (point_of_no_return)
  204.     return 0;
  205.  
  206.   BroadcastShutdownMsg (SHUTDOWN_ABORT, 0);
  207.   CleanUp (ShutdownCancelled);
  208. }
  209.  
  210. QMessage *
  211. GetShutdownMessage (void)
  212. {
  213.   QMessage *sm;
  214.  
  215.   for (;;)
  216.   {
  217.     if (sm = QGetMsg (ShutdownHandle))
  218.       break;
  219.     if (sm = QAllocMsg (sizeof (ShutdownMessage)))
  220.       break;
  221.     Delay (50);
  222.   }
  223.   return sm;
  224. }
  225.  
  226. QMessage *
  227. BroadcastShutdownMsg (ULONG status, ULONG time)
  228. {
  229.   ShutdownMessage *smsg;
  230.   QMessage *qmsg;
  231.  
  232.   qmsg = GetShutdownMessage ();
  233.   smsg = (ShutdownMessage *) qmsg -> qm_Data;
  234.   smsg -> sm_Status   = status;
  235.   smsg -> sm_TimeLeft = time;
  236.   QAddMsg (ShutdownHandle, qmsg);
  237.   return qmsg;
  238. }
  239.  
  240. void
  241. AbortableDelay (int seconds)
  242. {
  243.   int abort = 0, sec;
  244.   Message *msg;
  245.   ULONG mask;
  246.  
  247.   TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  248.   TimerReq -> tr_time.tv_secs  = seconds;
  249.   TimerReq -> tr_time.tv_micro = 0;
  250.   SendIO ((struct IORequest *) TimerReq);
  251.  
  252.   while (1)
  253.   {
  254.     mask = Wait (WaitMask);
  255.     if (mask & ShutdownMask)
  256.     {
  257.       if (msg = (Message *) GetMsg (ShutdownPort))
  258.       {
  259.         if (msg -> mn_Node.ln_Pri == 0) /* shutdown cancel request */
  260.         {
  261.           if (point_of_no_return || AbortableFlag == 0)
  262.         msg -> mn_Node.ln_Name = (APTR) -1;
  263.           else
  264.             abort = 1;
  265.         }
  266.         else /* shutdown delay request */
  267.         {
  268.           sec = msg -> mn_Node.ln_Pri;
  269.  
  270.       if (MaxTime > 0)
  271.           {
  272.         if ((MaxTime -= sec) < 0)
  273.               sec += MaxTime;
  274.             ShutdownTime += sec;
  275.         printf ("Shutdown delayed by %d seconds.\n", sec);
  276.             msg -> mn_Node.ln_Pri = sec;
  277.           }
  278.           else
  279.           {
  280.         msg -> mn_Node.ln_Name = (APTR) -1;
  281.         printf ("Shutdown delay refused.\n");
  282.           }
  283.         }
  284.         ReplyMsg ((struct Message *) msg);
  285.       }
  286.     }
  287.     if (mask & QueueMask)
  288.     {
  289.       /* Shutdown Queue reply: we aren't really interested
  290.          because we take our messages fresh from the reply
  291.      list when we need them.
  292.      The timer is still running so we just wait some more.
  293.       */
  294.     }
  295.     if (mask & SIGBREAKF_MASK || abort)
  296.     {
  297.       if (point_of_no_return)
  298.       {
  299.     printf (SorryTooLate);
  300.     continue;
  301.       }
  302.       if (!(mask & TimerMask))
  303.         AbortIO ((struct IORequest *) TimerReq);
  304.       WaitIO ((struct IORequest *) TimerReq);
  305.       SetSignal (0L, TimerMask);
  306.  
  307.       if (mask & SIGBREAKF_CTRL_C || abort)
  308.       {
  309.     if (mask & SIGBREAKF_CTRL_C)
  310.       printf ("CTRL-C\n");
  311.     CancelShutdown ();
  312.     printf ("Timer stopped, press CTRL-E or CTRL-F to reboot.\n");
  313.       }
  314.       if (mask & SIGBREAKF_CTRL_D) /* CTRL-D: speed up */
  315.       {
  316.     printf ("CTRL-D\n");
  317.     return;
  318.       }
  319.       if (!FastBoot)
  320.       {
  321.     FastBoot = 1;
  322.     if (mask & SIGBREAKF_CTRL_E) /* CTRL-E: fast reboot */
  323.         {
  324.       printf ("CTRL-E\n");
  325.       GoDown (5);
  326.         }
  327.     if (mask & SIGBREAKF_CTRL_F) /* CTRL-F: very fast reboot */
  328.     {
  329.       printf ("CTRL-F\n");
  330.       GoDown (0);
  331.     }
  332.       }
  333.       else
  334.     return;
  335.     }
  336.     if (mask & TimerMask) /* done waiting */
  337.       return;
  338.   }
  339. }
  340.  
  341. void
  342. GoingDownMessage (int seconds)
  343. {
  344.   if (seconds / 3600)
  345.     printf ("The system is going down in %d:%.2d hours.\n",
  346.             seconds / 3600, (seconds % 3600) / 60);
  347.   else if (seconds / 60)
  348.     printf ("The system is going down in %d:%.2d minutes.\n",
  349.             seconds / 60, seconds % 60);
  350.   else
  351.     printf ("The system is going down in %d seconds.\n", seconds);
  352.   fflush (stdout);
  353. }
  354.  
  355. int
  356. main (int argc, char *argv[])
  357. {
  358.   int shutdown_interval;
  359.   int cancel_flag = 0;
  360.   int opt, rest;
  361.  
  362.   SetTaskPri (FindTask (0L), 10);
  363.  
  364.   /*** Options ***/
  365.  
  366.   while ((opt = getopt (argc, argv, "cehiM:nNrs:t:SW")) != -1)
  367.     switch (opt)
  368.     {
  369.       case 'M': MaxTime = atoi (optarg); break;
  370.       case 'W': UnmountMode = UMNT_READONLY; break;
  371.       case 'S': UseShutdownLibFlag = 1; break;
  372.       case 'R': UnmountMode = UMNT_REMOUNT; break;
  373.       case 'n': AbortableFlag = 0; break;
  374.       case 'r': HaltFlag = HFLG_REBOOT; break;
  375.       case 'h': HaltFlag = HFLG_HALT; break;
  376.       case 'e': HaltFlag = HFLG_EXIT; break;      
  377.       case 't': ShutdownTime = atoi (optarg); break;
  378.       case 's': SyncTime = atoi (optarg); break;
  379.       case 'c': cancel_flag = 1; break;
  380.       case 'i': ShutdownTime = 0; MaxTime = 0; break;
  381.       default:
  382.         printf ("Usage: %s [-cehinNrSW] [-t <time>] [-M <max. time>] [-s <sync time>].\n", argv[0]);
  383.     exit (EXIT_FAILURE);
  384.     }
  385.  
  386.   /*** Libraries ***/
  387.  
  388.   if (HaltFlag)
  389.     IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37);
  390.   if (!(QueueBase = OpenLibrary ("queue.library", 3)))
  391.     CleanUp ("Failed to open queue.library.\n");
  392.   if (UseShutdownLibFlag)
  393.   {
  394.     if (!(ShutdownBase = OpenLibrary ("shutdown.library", 2)))
  395.       CleanUp ("Failed to open shutdown.library.\n");
  396.   }
  397.  
  398.   /*** Cancel shutdown ***/
  399.  
  400.   if (cancel_flag)
  401.     CancelRunningShutdown ();
  402.  
  403.   /*** Remount ***/
  404.  
  405.   if (UnmountMode == UMNT_REMOUNT)
  406.   {
  407.     Unmount (NULL, UnmountMode);
  408.     CleanUp ("Filesystems remounted.\n");
  409.   }
  410.  
  411.   /*** Shutdown queue ***/
  412.  
  413.   if ((QueueSignal = AllocSignal (-1)) == -1)
  414.     CleanUp (CantAllocatePort);
  415.   QueueMask = 1 << QueueSignal;
  416.   if (!(ShutdownHandle = QOpen ("shutdown", QMODE_SEND, QueueSignal)))
  417.   {
  418.     FreeSignal (QueueSignal);
  419.     CleanUp ("Failed to open shutdown queue.\n");
  420.   }
  421.  
  422.   /**** Timer device ***/
  423.  
  424.   if (!(TimerPort = CreateMsgPort ()))
  425.     CleanUp (CantAllocatePort);
  426.   if (!(TimerReq = (struct timerequest *)
  427.       CreateIORequest (TimerPort, sizeof (struct timerequest))))
  428.     CleanUp (OutOfMemory);
  429.   if (TimerErr = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerReq, 0))
  430.     CleanUp ("Can't open timer device.\n");
  431.   TimerMask = 1 << TimerPort -> mp_SigBit;
  432.  
  433.   /*** Don't start shutdown twice ***/
  434.  
  435.   Forbid ();
  436.   if (FindPort (ShutdownPortname))
  437.   {
  438.     Permit ();
  439.     CleanUp ("Shutdown is already running.\n");
  440.   }
  441.   Permit ();
  442.  
  443.   /*** Named message port ***/
  444.  
  445.   if (!(ShutdownPort = CreateMsgPort ()))
  446.     CleanUp (CantAllocatePort);
  447.   if (!(ShutdownPort -> mp_Node.ln_Name =
  448.     AllocMem (SpNameLen = strlen (ShutdownPortname) + 1, MEMF_PUBLIC)))
  449.     CleanUp (OutOfMemory);
  450.   bcopy (ShutdownPortname, ShutdownPort -> mp_Node.ln_Name, SpNameLen);
  451.   ShutdownPort -> mp_Node.ln_Pri = 0;
  452.   AddPort (ShutdownPort);
  453.   ShutdownMask = 1 << ShutdownPort -> mp_SigBit;
  454.  
  455.   /*** Shutdown interval loop ***/
  456.  
  457.   WaitMask = QueueMask | ShutdownMask | TimerMask | SIGBREAKF_MASK;
  458.  
  459.   while (ShutdownTime >= 10)
  460.   {
  461.     GoingDownMessage (ShutdownTime);
  462.     BroadcastShutdownMsg (SHUTDOWN_WARN, ShutdownTime);
  463.     shutdown_interval = ShutdownTime / 3;
  464.     ShutdownTime -= shutdown_interval;
  465.     if (rest = ShutdownTime % 5)
  466.     {
  467.       shutdown_interval += rest;
  468.       ShutdownTime -= rest;
  469.     }
  470.     AbortableDelay (shutdown_interval);
  471.   }
  472.   GoDown (ShutdownTime);
  473. }
  474.  
  475. void
  476. GoDown (int time)
  477. {
  478.   struct EasyStruct es = {
  479.     sizeof (struct EasyStruct), 0, "AmigaDOS", "The system is halted", "Ok"
  480.   };
  481.   QMessage *smo, *smi;
  482.   ULONG mask;
  483.  
  484.   if (UseShutdownLibFlag)
  485.   {
  486.     Shutdown (SHUTDOWN_EXTERN);
  487.   }
  488.  
  489.   if (time)
  490.   {
  491.     /* last warning */
  492.     GoingDownMessage (time);
  493.     BroadcastShutdownMsg (SHUTDOWN_NOW, time);
  494.     AbortableDelay (time);
  495.  
  496.     /* too late for writing */
  497.     BroadcastShutdownMsg (SHUTDOWN_UMOUNT, 0);
  498.   }
  499.   point_of_no_return = 1;
  500.  
  501.   printf ("The system is going down, unmounting filesystems.\n");
  502.   fflush (stdout);
  503.   Unmount (NULL, UnmountMode);
  504.   AbortableDelay (SyncTime);
  505.  
  506.   /*** all done, who turns off the light? ***/
  507.   if (time && HaltFlag != HFLG_EXIT)
  508.   {
  509.     smo = BroadcastShutdownMsg (SHUTDOWN_HALT, 0);
  510.  
  511.     TimerReq -> tr_node.io_Command = TR_ADDREQUEST;
  512.     TimerReq -> tr_time.tv_secs  = 5;
  513.     TimerReq -> tr_time.tv_micro = 0;
  514.     SendIO ((struct IORequest *) TimerReq);
  515.  
  516.     for (;;) /*** Wait for the last broadcast to be replied ***/
  517.     {
  518.       mask = Wait (TimerMask | QueueMask);
  519.       if (mask & QueueMask)
  520.         while (smi = QGetMsg (ShutdownHandle))
  521.         {
  522.       if (smi == smo)
  523.         mask |= TimerMask;
  524.           QFreeMsg (smi, sizeof (ShutdownMessage));
  525.         }
  526.       if (mask & TimerMask)
  527.     break;
  528.     }
  529.   }
  530.   switch (HaltFlag)
  531.   {
  532.     case HFLG_HALT:
  533.       printf ("The system is halted.\n");
  534.       if (IntuitionBase)
  535.         BuildEasyRequest (NULL, &es, NULL);
  536.       Delay (10); /* wait 0.5 seconds */
  537.       Disable ();
  538.       while (1);
  539.     case HFLG_REBOOT:
  540.       ColdReboot ();
  541.     case HFLG_EXIT:
  542.       CleanUp ("Done.\n");
  543.   }
  544. }
  545.